#include "netdisk.h"

//如果不返回sfd就要使用发送内核控制信息的技术
int get_tcp_socket(char* ip,char* port)
{
    int sfd;
    sfd=socket(AF_INET,SOCK_STREAM,0);//初始化socket网络描述符,对应一块缓冲区
    ERROR_CHECK(sfd,-1,"socket")
    //在bind之前去执行setsockopt，设定端口重用
    int reuse=1,ret;
    ret=setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(int));
    ERROR_CHECK(ret,-1,"setsockopt")
    struct sockaddr_in ser_addr;
    bzero(&ser_addr,sizeof(ser_addr));//清空
    ser_addr.sin_family=AF_INET;//代表进行ipv4通信
    ser_addr.sin_addr.s_addr=inet_addr(ip);//把ip的点分十进制转化为网络字节序
    ser_addr.sin_port=htons(atoi(port));//把端口号转为网络字节序
    //开始绑定
    ret=bind(sfd,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
    ERROR_CHECK(ret,-1,"bind")
    //开始监听,端口就开启了
    ret=listen(sfd,10);
    ERROR_CHECK(ret,-1,"listen")
    return sfd;
}

//用于和客户端通信的子进程
int child_func(pchild_use p)
{
    int fd=p->fd;
    train_t train;
	int len;
    while(1){
        bzero(train.buf,sizeof(train.buf));
        // 接受指令长度
        train.data_len=recv(fd,&len,sizeof(int),0);
		//printf("in ser_main train.data_len=%d\n",len);
       if(train.data_len==0)
		{
			printf("CLIENT EXIT!\n");
			close(p->fd);
			free(p);
			exit(1);
		}
		// 接受指令的字符串
		//recvn(fd,train.buf,train.data_len);//收火车车厢
		recv(fd,train.buf,sizeof(train.buf),0);
		//printf("in ser_main received %s\n",train.buf);
		if(strncmp("cd",train.buf,2) == 0)
		{
			//printf("this is cd\n");
			do_cd(p,train.buf);
		}else if(strncmp("ls",train.buf,2) == 0)
		{
			do_ls(p,train.buf);
		}else if( strncmp("puts",train.buf,4)== 0)
		{
			printf("this is ser_puts,buf=%s",train.buf);
			do_puts(p,train.buf);
		}else if( strncmp("gets",train.buf,4)== 0)
		{
			do_gets(p,train.buf);

		}else if( strncmp("remove",train.buf,6)== 0)
		{
			do_remove(p,train.buf);

		}else if(strncmp("pwd",train.buf,3) == 0) 
		{
			//printf("ser gets pwd cmd,buf=%s\n",train.buf);
			do_pwd(p,train.buf);

		}else 
		{
			continue ;
		}
    }

}

int recvn(int fd_recv,char* recv_buf,int len)
{
	int sum=0;
	int received=0;
	while(sum<len)
	{
		received=recv(fd_recv,&recv_buf[sum],len-sum,0);
		sum+=received ;
	}
	//recv_buf[sum]='\0';
	return sum;
}
int sendn(int fd_send,char* send_buf,int len)
{
	int sum=0 ;
	int sended;
	while(sum<len)
	{
		sended=send(fd_send,send_buf+sum,len-sum,0);
		sum+=sended ;
	}
	return sum ;
}
void do_cd(pchild_use p,char* buf)
{
	printf("%s",buf);
	char dir[128]="";
	//strcpy(dir,buf+3);
	sscanf(buf+3,"%s",dir);//将buf+3位置的数据读入dir,即cd空格后面的路径
	//printf("%s\n",dir);
	chdir(dir);//改变当前路径至dir
	getcwd(dir,sizeof(dir));//获取当前路径并存入dir中
	int len=strlen(dir);
	send(p->fd,&len,sizeof(int),0);//发送要发送的文件的字节数
	sendn(p->fd,dir,len);//发送文件内容
	//printf("%s\n",dir);
	//printf("cd send success\n");
}

void do_ls(pchild_use p,char* buf)
{
	printf("%s",buf);
	DIR* pdir=opendir("./");
	if(!pdir)
	{
		perror("opendir");
		return ;
	}
	struct dirent* mydir ;
	int len ;
	while((mydir=readdir(pdir))!=NULL)//读取目录
	{
		if(strncmp(mydir->d_name,".",1)==0||strncmp(mydir->d_name,"..",2)==0)//忽略.和..
		{
			continue ;
		}
		struct stat mystat;
		bzero(&mystat, sizeof(stat));
		stat(mydir->d_name,&mystat);//获取某个文件的信息
		bzero(buf,Num);
		sprintf(buf,"%-2s%-20s %10ldB",file_type(mystat.st_mode),mydir->d_name,mystat.st_size);
		len=strlen(buf);
		send(p->fd,&len,sizeof(int),0);//发送数据给客户端
		sendn(p->fd,buf,len);
	}
	len=0;//发送完成标志
	send(p->fd,&len,sizeof(int),0);
}

//客户端上传文件
void do_puts(pchild_use p,char* buf)
{
	printf("%s",buf);
	char file_name[256];
	int file_pos=5 ;
	bzero(file_name,256);
	while(sscanf(buf+file_pos,"%s",file_name)==1)
	{
		file_pos+=strlen(file_name)+1 ;//为了puts后面跟多个文件名
		printf("%s\n",file_name);
		if(download(p->fd,file_name)==0)
		{
			printf("file-> %s download success \n",file_name);
		}else
		{
			printf("file -> %s download failed \n",file_name);
		}
	}
}

//发文件给客户端
void do_gets(pchild_use p,char* buf)
{
	printf("%s",buf);
	char file_name[256];
	int file_pos=5;
	bzero(file_name,256);
	while(sscanf(buf+file_pos,"%s",file_name)==1)//下载多个文件
	{
		file_pos+=strlen(file_name)+1; 
		if(upload(p->fd,file_name)==0)
		{
			printf("file-> %s upload success\n",file_name);
		}else 
		{
			printf("file-> %s upload failed\n",file_name);
		}

	}

}

void do_remove(pchild_use p,char* buf)
{
	printf("%s",buf);
	char cmd[256]={0};
	sprintf(cmd,"rm -f %s",buf+6);//一次删除一个
	system(cmd);//执行删除命令
	bzero(buf,Num);
	sprintf(buf, "%s removed",buf+7);
	int len=strlen(buf);
	send(p->fd,&len,sizeof(int),0);
	sendn(p->fd,buf,len);
}

void do_pwd(pchild_use p,char* buf)
{
	printf("%s",buf);
	//printf("buf size=%ld\n",sizeof(buf));
	//printf("in do_pwd buf=%s\n",buf);
	bzero(buf,Num);
	getcwd(buf,Num);
	//printf("after gercwd buf=%s\n",buf);
	int len=strlen(buf);
	send(p->fd,&len,sizeof(int),0);
	//printf("pwd=%s\n",buf);
	sendn(p->fd,buf,len);
}

int upload(int fd_up,char* file_name)
{
	int fd_file=open(file_name,O_RDONLY);
	ERROR_CHECK(fd_file,-1,"open")
	char *read_buf=(char*)malloc(Num);
	bzero(read_buf,sizeof(read_buf));
	int readed;
	while(1)
	{
		readed=readn(fd_file,read_buf,Num);//读文件到read_buf中并返回读取的字节数
		if(readed <Num)//文件的最后一部分
		{
			send(fd_up,&readed,sizeof(int),0);
			sendn(fd_up,read_buf,readed);
			break ;
		}else
		{
			send(fd_up,&readed,sizeof(int),0);
			sendn(fd_up,read_buf,readed);
		}
	}
	int flag=0;
	send(fd_up,&flag,sizeof(flag),0);
	close(fd_file);
	return 0 ;
}
//接收文件
int download(int fd_down,char* file_name)
{
	int fd_file=open(file_name, O_WRONLY|O_CREAT,0666 );
	ERROR_CHECK(fd_file,-1,"open")
	char* write_buf=(char*)malloc(Num);
	bzero(write_buf,sizeof(write_buf));
	int writed;
	while(1)
	{
		recv(fd_down,&writed,sizeof(int),0);
		if(writed==0)
		{
			break ;
		}
		recvn(fd_down,write_buf,writed);
		writen(fd_file,write_buf,writed);
	}
	close(fd_file);
	return 0 ;
}

int readn(int fd_read,char* read_buf,int len)
{
	int sum=0 ;
	int readed ;
	while(sum<len)//一直读文件，直至把read_buf读满
	{
		readed=read(fd_read,&read_buf[sum],len-sum);
		if(readed==0)
		{
			break ;
		}
		sum+=readed ;
	}
	return sum ;		
}

int writen(int fd_write,char* write_buf,int len)
{
	int sum=0;
	int writed;
	while(sum<len)
	{
		writed=write(fd_write,write_buf+sum,len-sum);
		sum+=writed;
	}
	return sum ;
}
char* file_type(mode_t md)
{
	if(S_ISREG(md))
	{
		return "-";	
	}else if(S_ISDIR(md))
	{
		return "d";
	}else if(S_ISFIFO(md))
	{
		return "p";
	}else 
	{
		return "o" ;
	}
}